package org.sfx.diagnostics

import javafx.stage.Stage
import javafx.stage.StageStyle
import javafx.scene.Scene
import javafx.scene.layout.Pane
import javafx.scene.Group
import javafx.stage.PopupWindow
import javafx.scene.shape.Path
import javafx.scene.shape.MoveTo
import javafx.scene.shape.LineTo
import javafx.scene.shape.ClosePath
import javafx.stage.Popup
import javafx.stage.Window
import javafx.stage.Screen
import scala.collection.mutable.WeakHashMap
import org.sfx.rich.Enrich._
import javafx.scene.input.MouseEvent
import javafx.event.EventType
import javafx.scene.Node

class SpyScopeGlass(owner: Window) extends Stage(StageStyle.TRANSPARENT) {
  this.setWidth(Screen.getPrimary().getBounds().getWidth())
  this.setHeight(Screen.getPrimary().getBounds().getHeight())

  val screenGroup = new Group()
  val windowGroup = new Group()
  val sceneGroup = new Group()
  val scene = new Scene(screenGroup) {
    /*override def impl_processMouseEvent(mouseEvent: MouseEvent): Unit = {
      val newMouseEvent = MouseEvent.impl_mouseEvent(
          mouseEvent.getX() - owner.getX() - owner.getScene().getX(),
          mouseEvent.getY() - owner.getY() - owner.getScene().getY(),
          mouseEvent.getScreenX(),
          mouseEvent.getScreenY(),
          mouseEvent.impl_getWheelRotation(),
          mouseEvent.getButton(),
          mouseEvent.getClickCount(),
          mouseEvent.isShiftDown(),
          mouseEvent.isControlDown(),
          mouseEvent.isAltDown(),
          mouseEvent.isMetaDown(),
          MouseEvent.impl_getPopupTrigger(mouseEvent),
          mouseEvent.isPrimaryButtonDown(),
          mouseEvent.isMiddleButtonDown(),
          mouseEvent.isSecondaryButtonDown(),
          mouseEvent.getEventType().asInstanceOf[EventType[MouseEvent]])

      if (SpyScopeGlass.this.isFocused()) {
        owner.setFocused(true)
        owner match {
          case ownerStage: Stage => ownerStage.toFront()
          case _ =>
        }
      }
      
      owner.getScene().impl_processMouseEvent(newMouseEvent)
    }*/
  }
  screenGroup.getChildren().add(windowGroup)
  windowGroup.getChildren().add(sceneGroup)
  scene.setFill(null)
  sceneGroup.layoutXProperty().bind(owner.getScene().xProperty())
  sceneGroup.layoutYProperty().bind(owner.getScene().yProperty())
  this.setScene(scene)
  this.setX(0.0)
  this.setY(0.0)
  owner.xProperty().addChangeListener { (_, _, newValue) =>
    windowGroup.setLayoutX(newValue.doubleValue())
  }
  owner.yProperty().addChangeListener { (_, _, newValue) =>
    windowGroup.setLayoutY(newValue.doubleValue())
  }
  
  this.windowGroup.setDisable(true)
  this.initOwner(owner)
  this.show()
}

object SpyScopeGlass {
  private val spyScopeGlasses = new WeakHashMap[Window, SpyScopeGlass]
  private val lock = new Object
  
  def on(window: Window): SpyScopeGlass = {
    val spyScopeGlass = this.lock.synchronized {
      spyScopeGlasses.getOrElseUpdate(window, new SpyScopeGlass(window))
    }
    spyScopeGlass.show()
    spyScopeGlass
  }

  def onAny(any: Any): Option[SpyScopeGlass] = any match {
    case window: Window => this.lock.synchronized { Some(SpyScopeGlass.on(window)) }
    case scene: Scene => scene.getWindow() match {
      case null => None
      case window => this.lock.synchronized { Some(SpyScopeGlass.on(window))}
    }
    case node: Node => node.getScene() match {
      case null => None
      case scene => scene.getWindow() match {
        case null => None
        case window => this.lock.synchronized { Some(SpyScopeGlass.on(window))}
      }
    }
    case _ => None
  }
}
